package tools;

import org.junit.Assert;
import org.junit.jupiter.api.Assertions;
import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.opentest4j.AssertionFailedError;

import java.time.Duration;
import java.util.List;
import java.util.Optional;

public class PageUtil {

    /**
     * 检测页面元素是否存在
     *
     * @param webDriver WebDriver对象
     * @param locator   元素的位置
     * @param timeout   等待元素出现的最长时间
     * @return 如果元素存在则返回
     */
    public static Optional<WebElement> findElement(WebDriver webDriver, By locator, Duration timeout) {
        try {
            WebDriverWait wait = new WebDriverWait(webDriver, timeout);
            WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(locator));
            return Optional.of(element);
        } catch (Exception ex) {
            return Optional.empty();
        }
    }

    public static Optional<WebElement> findElementRelative(WebDriver webDriver,final WebElement parent,final By locator, Duration timeout) {
        try {
            WebDriverWait wait = new WebDriverWait(webDriver, timeout);
            WebElement element = wait.until(presenceOfElementLocatedRelative(parent,locator));
            return Optional.of(element);
        } catch (Exception ex) {
            return Optional.empty();
        }
    }

    public static ExpectedCondition<WebElement> presenceOfElementLocatedRelative(final WebElement parent,final By locator) {
        return new ExpectedCondition<WebElement>() {
            public WebElement apply(WebDriver driver) {
                return parent.findElement(locator);
            }

            public String toString() {
                return "presence of element located by: " + locator;
            }
        };
    }

    public static List<WebElement> findElements(WebDriver driver, By locator, Duration duration) {
        WebDriverWait wait = new WebDriverWait(driver, duration);
        return wait.until(webDriver-> {
            List<WebElement> elements = webDriver.findElements(locator);
            if (elements==null|| elements.size()==0){
                return null;
            }
            return elements;
        });
    }

    /**
     * 建议使用该方法替换默认生成的
     * driver.findElement\((By.*?)\)\.click\(\);
     * PageUtil.findAndClick\(driver,$1,Duration\.ofSeconds\(5\)\);
     * @param driver WebDriver
     * @param locator By locator
     * @param timeout Duration
     */
    public static void findAndClick(WebDriver driver, By locator, Duration timeout){
        Optional<WebElement> element1 = findElement(driver, locator, timeout);
        Assertions.assertTrue(element1.isPresent());
        doClick(driver,element1.get());
    }

    /**
     * 建议使用该方法替换默认生成的
     * driver.findElement\((By.*?)\)\.sendKeys\((.*?)\);
     * PageUtil.findAndInput\(driver,$1,Duration\.ofSeconds\(5\),$2\);
     * @param driver
     * @param locator
     * @param timeout
     * @param inputs
     */
    public static void findAndInput(WebDriver driver,By locator, Duration timeout, String inputs){
        WebElement webElement = findElement(driver, locator, timeout).orElseThrow(AssertionFailedError::new);
        webElement.sendKeys(Keys.HOME,Keys.chord(Keys.SHIFT,Keys.END),inputs);
    }

    public static void doClick(WebDriver webDriver, WebElement element) {
        //TODO 条件不充分
        JavascriptExecutor js = (JavascriptExecutor) webDriver;
        js.executeScript("arguments[0].scrollIntoView()",element);
        try {
            element.click();
        }catch (Exception e){
            js.executeScript("arguments[0].click()", element);
        }

    }

    public static void sendKeys(WebDriver driver, WebElement element,String inputs){
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("arguments[0].scrollIntoView()",element);
        element.sendKeys(inputs);
    }
    public static void doClick(WebDriver webDriver,By locator,Duration timeout){
        Optional<WebElement> element = findElement(webDriver, locator, timeout);
        Assertions.assertTrue(element.isPresent());
        if(element.get().isEnabled()) {
            PageUtil.doClick(webDriver, element.get());
        }
    }
    public static String getText(WebDriver webDriver,By locator,Duration timeout){
        Optional<WebElement> element = findElement(webDriver, locator, timeout);
        Assertions.assertTrue(element.isPresent());
        return getText(webDriver, element.get());
    }

    public static String getText(WebDriver driver, WebElement element){
        JavascriptExecutor js = (JavascriptExecutor) driver;
        return (String) js.executeScript("return arguments[0].innerText;",element);
    }
    public static void checkCancelAndClickConfirm(WebDriver driver, Duration duration){
        //check cancel
        WebElement cancelButton1 = PageUtil.findElement(driver, By.id("CancelButton"), duration).get();
        Assertions.assertNotNull(cancelButton1);
        //check and click confirm
        WebElement confirmButton = PageUtil.findElement(driver, By.id("ConfirmButton"), duration).get();
        PageUtil.doClick(driver, confirmButton);
    }
}
